from typing import Any, Iterable
import scrapy
from scrapy.http import HtmlResponse
from scrapy.http import Response
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

from hello_selenium.scrapy_settings_config import ScrapySettingsConfig


class UserListSpider(scrapy.Spider):
    name = "user_list"

    def __init__(self, config: ScrapySettingsConfig, *args, **kwargs):
        super(UserListSpider, self).__init__(*args, **kwargs)
        self.config = config

    @classmethod
    def from_crawler(cls, crawler, *args, **kwargs):
        # Initialize the config class
        config = ScrapySettingsConfig(crawler)

        # Return an instance of the spider with the config
        return cls(config=config, *args, **kwargs)

    def start_requests(self) -> Iterable[scrapy.Request]:
        yield scrapy.Request(
            url=f"{self.config.remote_host}/user/list/",
            callback=self.parse,
            meta={'wait_selector': "table.el-table__body>tbody>tr>td>div.cell"}
        )

    def parse(self, response: Response, **kwargs: Any) -> Any:
        # Iterate rows in table.
        for row in response.css("table.el-table__body>tbody>tr"):
            # Get all columns.
            columns = row.css("td.el-table__cell ")

            yield {
                "avatarUrl": columns[1].css("div.cell img::attr(src)").get(),
                "username": columns[2].css("div.cell::text").get(),
                "fullName": columns[3].css("div.cell::text").get(),
            }

        yield from self.handle_pagination(self.driver, response)

    def handle_pagination(self, driver, response: Response) -> Any:
        next_button = driver.find_element(
            By.CSS_SELECTOR, "div.table-container div.el-pagination button.btn-next")

        if next_button and not next_button.get_attribute("disabled"):
            page_input_selector = (
                By.CSS_SELECTOR, "div.el-pagination__editor input.el-input__inner")

            # Get current page index
            current_page_index = WebDriverWait(driver, 30).until(
                EC.presence_of_element_located(page_input_selector)
            ).get_attribute("value")

            next_button.click()

            # Wait until the text changes
            WebDriverWait(driver, 30).until(lambda driver: driver.find_element(
                *page_input_selector).get_attribute("value") != current_page_index)

            # For testing purpose ONLY.
            # with open("d:/page_source.html", "w", encoding="utf-8") as file:
            #     file.write(driver.page_source)

            # Create a new response with the updated content
            new_response = HtmlResponse(
                url=response.url,
                body=driver.page_source,
                encoding='utf-8',
                request=response.request
            )

            # Parse the new content
            yield from self.parse(new_response)
